#include "Packet.h"

namespace Network {

Packet::Packet() {
	id = 0;
	client_id = 0;
	size = 12;
	pos_ = 0;
	packed = false;
}

Packet::Packet(const Packet & packet) {
	if (&packet == this)
		return;

	id = packet.id;
	client_id = packet.client_id;
	size = packet.size;

	ba = packet.ba;
}

Packet::~Packet() {

}

const char * Packet::data() {
	return ba.constData();
}

void Packet::data(char * buf, int size) {
	ba = QByteArray((const char *)buf, size);
	packed = false;
	pos_ = 0;
}

void Packet::pack() {
	if (packed)
		return;
/*
	ba.push_front(QByteArray::fromRawData((const char *)&size, 4));
	ba.push_front(QByteArray::fromRawData((const char *)&client_id, 4));
	ba.push_front(QByteArray::fromRawData((const char *)&id, 4));

	packed = true;
*/
}

void Packet::unpack() {
	if (!packed)
		return;

/*
	id = *((int*)(ba.left(4).constData()));
	ba.remove(0, 4);

	client_id = *((int*)(ba.left(4).constData()));
	ba.remove(0, 4);

	size = *((int*)(ba.left(4).constData()));
	ba.remove(0,4);


	packed = false;

	pos_ = 0;*/
}

QString Packet::dump() {
	QString result;

	result = QString("ID: %1\n").arg(id);
	result += QString("Client ID: %1\n").arg(client_id);
	result += QString("Size: %1\n").arg(size);

	int pad;
	if (packed)
		pad = 0;
	else
		pad = 12;

	for (int i = 0; i < size-pad; ++i) {
		result += QString("%1 ").arg((int)(data()[i]));
		if ((i+1)%4 == 0)
			result += "\n";
	}

	return result;
}

void Packet::seek(int offset, int mode) {
	switch (mode) {
		case 0:
			pos_ = qMin(offset, size-12);
			break;

		case 1:
			pos_ += offset;
			pos_ = qMax(pos_, 0);
			pos_ = qMin(pos_, size-12);
			break;

		case 2:
			pos_ = size - 12 - offset;
			pos_ = qMax(pos_, 0);
			pos_ = qMin(pos_, size-12);
			break;
	}
}

Packet & Packet::operator << (int i) {
	ba.append((const char *)(&i), 4);
	pos_ += 4;
	size += 4;
	return *this;
}

Packet & Packet::operator << (const QString & s) {
	ba.append(s.toStdString().c_str());
	ba.append('\0');
	pos_ += s.length()+1;

	// wyrównujemy dane do 32 bitów
	int pad = 4 - (pos_ % 4);
	if (pos_ % 4 != 0) {
		ba.append("\0\0\0\0", pad);
		pos_ += pad;
	}

	size = 12 + pos_;

	return *this;
}

Packet & Packet::operator << (const QByteArray & b) {
	// zapisujemy rozmiar
	(*this) << b.length();

	// zapisujemy tablicę
	ba.append(b);
	pos_ += b.length();

	// wyrównujemy dane do 32 bitów
	int pad = 4 - (pos_ % 4);
	if (pos_ % 4 != 0) {
		ba.append("\0\0\0", pad);
		pos_ += pad;
	}

	size = 12 + pos_;

	return *this;
}

Packet & Packet::operator >> (int & i) {
	i = *((int*)(ba.constData()+pos_));

	pos_ += 4;

	return *this;
}

Packet & Packet::operator >> (QString & s) {
	int i;
	for (i = 0; i < ba.length()-pos_; ++i)
		if (ba.at(pos_+i) == 0)
			break;

	++i;

	s = QString(ba.constData() + pos_);

	pos_ += i;
	// wyrównujemy dane do 32 bitów
	int pad = 4 - (pos_ % 4);
	if (pos_ % 4 != 0) {
		pos_ += pad;
	}
	return *this;
}

Packet & Packet::operator >> (QByteArray & b) {
	int len;
	(*this) >> len;

	b = QByteArray(ba.constData() + pos_, len);

	pos_ += len;

	// wyrównujemy dane do 32 bitów
	int pad = 4 - (pos_ % 4);
	if (pos_ % 4 != 0) {
		pos_ += pad;
	}

	return *this;
}

} // namespace Network
